#include "StdAfx.h"
#include "Executor.h"

vector<Task*> Executor::taskList;
enum Executor::COMMAND_TYPE;
enum Executor::KEYWORD_TYPE;

//int main()
//{
//        UserInterface output;
//        Executor execute;
//        Storage store;
//        string inputLine;
//        string feedback;
//    
//        //output.printMessage("welcome");
//        //cout << "Welcome" << endl;								 //temp
//
//        execute.loadVect();
//
//        while (feedback != "Exiting...") {
//			//output.printMessage("enter task");
//			//cout << "enter task:" << endl;                       //temp
//			getline(cin, inputLine);
//			feedback = execute.executeCommand(inputLine);
//			output.printMessage(feedback);        
//            //cout << feedback << endl;                            //temp
//            store.storeResult(execute.taskList);
//                
//        }
//
//		store.clearLog();
//        
//        return 0;
//}

//void Executor::loadVect()
//{
//        fstream fileStore;
//        fileStore.open("tasker.txt",ios::out);
//
//        string str;
//        int i=0;
//
//        while(!fileStore.eof()){
//			getline(fileStore,str);
//            executeAdd(str);
//        }
//		fileStore.close();
//}

void Executor::loadVectToExecutor()
{
	Storage store;

	//taskList = store.loadVect();

	taskList = store.loadVectAlternate();		//still got some error
}

void Executor::storeVectFromExecutor()
{
	Storage store;

	store.storeResult(taskList);
}
            

Executor::COMMAND_TYPE Executor::determineCommandType(string commandTypeString)
{
        if(commandTypeString == "add") {
            return COMMAND_TYPE::ADD;
		} else if (commandTypeString == "delete") {
            return COMMAND_TYPE::DELETE;
        } else if (commandTypeString == "show") {
            return COMMAND_TYPE::SHOW;
        } else if (commandTypeString == "search") {
            return COMMAND_TYPE::SEARCH;
        } else if (commandTypeString == "clear") {
            return COMMAND_TYPE::CLEAR;
        } else if (commandTypeString == "done") {
            return COMMAND_TYPE::DONE;
        } else if (commandTypeString == "help") {
            return COMMAND_TYPE::HELP;
        } else if (commandTypeString == "exit") {
            return COMMAND_TYPE::EXIT;
		} else {
			return COMMAND_TYPE::INVALID;
		}
}

Executor::KEYWORD_TYPE Executor::determineKeywordType(string keywordTypeString)
{
	if(keywordTypeString == "-date")
		return KEYWORD_TYPE::DATE;
    if(keywordTypeString == "-starts")
		return KEYWORD_TYPE::STARTS;
    if(keywordTypeString == "-ends")
        return KEYWORD_TYPE::ENDS;
    if(keywordTypeString == "-detail")
        return KEYWORD_TYPE::DETAIL;
    if(keywordTypeString == "-impt")
        return KEYWORD_TYPE::IMPT;
	if(keywordTypeString == "-done")
        return KEYWORD_TYPE::IMPT;
}

string Executor::toLowerCase(string word)
{
    for(int i=0; i< word.size(); i++){
		word[i]=tolower(word[i]);
    }

    return word;
}

string Executor::getFirstWord(string &inputLine) 
{
    string firstWord = inputLine.substr(0, inputLine.find(' '));
    return firstWord;
}

//string Executor::removeFirstWord(string &inputLine){
//        int i = inputLine.find(' ');
//        if(i != -1)
//                inputLine.erase(0, i+1);
//        else
//                inputLine.clear();
//
//        return inputLine;
//}

string Executor::extractFirstWord(string &inputLine)
{
	string firstWord = "";
    int i = inputLine.find(' ');
    firstWord = inputLine.substr(0, i);
    if(i != -1)
		inputLine.erase(0, i+1);
    else
		inputLine.clear();
        
    return firstWord;
}

string Executor::executeCommand(string &inputLine)
{
    Validator checker;
	Storage store;

    string commandTypeString  = extractFirstWord(inputLine);
    commandTypeString = toLowerCase(commandTypeString);

    if(checker.isValidCommand(commandTypeString)) {
        COMMAND_TYPE commandType = determineCommandType(commandTypeString);
        string response;        
        switch (commandType) {
		case ADD:
			response = executeAdd(inputLine);
			break;
        case DELETE: 
            response = executeDelete(inputLine);
			break;
        case SHOW: 
            return executeShow(inputLine);
        case SEARCH: 
            return executeSearch(inputLine);
        case CLEAR: 
            response = executeClear(inputLine);
			break;
        case DONE: 
            response = executeDone(inputLine);
			break;
        case HELP: 
            return executeHelp();
        case EXIT: 
            return executeExit();
		default:
			return "Unimplemented Functionality";
		}
		storeVectFromExecutor();
		return response;
	}
	else 
		return executeInvalid(inputLine);
}

string Executor::makeTask(string &inputLine, Task* &t)
{
	UserInterface output;
	Validator checker;
    string response = "Task Formatted";

    string name = extractFirstWord(inputLine);
	if(checker.isValidTaskName(name))
    {
		t->appendToName(name);
        while(!inputLine.empty())
        {
                string followingWord = extractFirstWord(inputLine);

                if(checker.isValidKeyword(followingWord)) {
					KEYWORD_TYPE keywordType = determineKeywordType(followingWord);

                    switch(keywordType) 
                    {
                    case DATE:
						{
                            string date = extractFirstWord(inputLine);
                            if(checker.isValidDate(date))
                                    t->setDate(date);
                            else
                                    response = output.generateMessage("invalidDate", date);
                                    //response = "invalidDate";				//temp
                            break;
						}
					case STARTS:
						{
							string st_time = extractFirstWord(inputLine);
							if(checker.isValidTaskTime(st_time))
									t->setStartTime(makeInt(st_time));
                            else
                                    response = output.generateMessage("invalidTime", st_time);
                                    //response = "invalidTime";				//temp
                            break;
						}
					case ENDS:
						{
							string end_time = extractFirstWord(inputLine);
							if(checker.isValidTaskTime(end_time))
									t->setEndTime(makeInt(end_time));
                            else
                                    response = output.generateMessage("invalidTime", end_time);
                                    //response = "invalidTime";				//temp
                            break;
						}
					case DETAIL:
						{
							do{
								string detail = extractFirstWord(inputLine);
								t->appendToDetail(detail);
										
								followingWord = getFirstWord(inputLine);
							}while(!checker.isValidKeyword(followingWord) && !inputLine.empty());
                            break;
						}
					case IMPT:
						{
							t->setImpt(true);
                            break;
						}
					case DONE:
						{
							t->setDone(true);
                            break;
						}
					}

				}
                else 
					t->appendToName(followingWord);
		}
			//in future : add a function here that sets 
			// floating tasks(tasks without date AND time) to the nearest unoccupied day
	}
    else
		response = output.generateMessage("invalidName", name);
        //response = "invalidName";												//temp

    return response;
}


string Executor::executeAdd(string &inputLine) 
{
    UserInterface output;
    Task *t;
    Storage store;
    string result, response;

    t = new Task();
    result = makeTask(inputLine, t);

    if(result == "Task Formatted")
    {
		taskList.push_back(t);
        // will return a generated/formatted string (i.e "Group Meeting at 5pm has been added")
        // am including the task, t, so that it uses the info of t to structure this above string
		response = output.generateMessage("added", t->getName());
        //response = "ADDED";                                                                                                     //temp
    }

    else
        response = result;

    return response;
}

int Executor::makeInt(string taskNum_str)
{
    return atoi(taskNum_str.c_str());
}

string Executor::executeDelete(string &inputLine) 
{
	UserInterface output;
    Storage store;
    Validator checker;
    string response;

    string taskNum_str = extractFirstWord(inputLine);
    if(checker.isInt(inputLine))
    {
		int taskNum_int = makeInt(taskNum_str);
        int actual_taskNum_int = taskNum_int - 1;
        if(checker.isValidTaskNumber(actual_taskNum_int, taskList))
        {       
            string deletedTask = taskList[actual_taskNum_int]->getName();
            taskList.erase(taskList.begin()+actual_taskNum_int);
            // "deleted task num" string generated
            response = output.generateMessage("deleted", deletedTask);
            //response = "DELETED";                                                   //temp
        }
        else
		{
			//invalid task num string generated
            response = output.generateMessage("invalidTaskNum", taskNum_str); 
            //response = "invalidTaskNum";                                    //temp
        }
	}
	else
	{
		//"not an int" string generated
	    response = output.generateMessage("notInt", taskNum_str);
	    //response = "notInt";                                                                    //temp
	}

	return response;
}

string Executor::executeInvalid(string &inputLine) 
{      
    UserInterface output;

    string response = output.generateMessage("invalidCommand", inputLine);
    //string response = "invalidCommand dont have any execution";             //temp

    return response;
}

string Executor::executeShow(string &inputLine)
{
	UserInterface output;
	Validator checker;
	ostringstream outstr;
    string response = EMPTY;

    string firstWord = extractFirstWord(inputLine);

    if(firstWord == "")                                     //isEmptyString(inputLine))
    {
		if(taskList.size() == 0)
		{
			outstr << output.generateMessage("isEmptyFile", "");
		}
		else
		{
			for(int i = 0; i < taskList.size(); i++)
			{
				outstr << i+1 << ". " << taskList[i]->getName() << TAB << taskList[i]->getDate() << "\n";
			}
		}

		response = outstr.str();
    }
    else if(firstWord == "impt")
    {
        for(int i = 0; i < taskList.size(); i++)
        {       
            if(taskList[i]->getImpt() == true)
				outstr << i+1 << ". " << taskList[i]->getName() << TAB << taskList[i]->getDate() << "\n";
        }

		response = outstr.str();
    }
    else if(firstWord == "detail")
    {
		string taskNum_str = extractFirstWord(inputLine);
		if(checker.isInt(inputLine))
		{
			int taskNum_int = makeInt(taskNum_str);
            int actual_taskNum_int = taskNum_int - 1;
            if(checker.isValidTaskNumber(actual_taskNum_int, taskList))
            {       
				outstr << taskNum_int << ". " << taskList[actual_taskNum_int]->getName() << TAB << taskList[actual_taskNum_int]->getDetail() << endl;
				
				response = outstr.str();
			}
            else
            {
				//invalid task num string generated
                response = output.generateMessage("invalidTaskNum", taskNum_str); 
                //response = "invalidTaskNum";                                    //temp
            }
		}
		else
		{       
			//"not an int" string generated
            response = output.generateMessage("notInt", taskNum_str);
            //response = "notInt";                                                                    //temp
		}
	}
    else
    {
		string date = firstWord;
        if(checker.isValidDate(date))
        {
            for(int i = 0; i < taskList.size(); i++)
            {       
                if(date == taskList[i]->getDate())
                    outstr << i+1 << ". " << taskList[i]->getName() << TAB << taskList[i]->getDate() << "\n";
            }

			response = outstr.str();
        }
        else
            response = output.generateMessage("invalidDate", date);
            //response = "invalidDate";                               //temp
    }
        
    return response;
}

string Executor::executeSearch(string &inputLine)
{
	UserInterface output;
    size_t found;
    int match = 0;
	ostringstream outstr;
    string response = output.generateMessage("matchUnfound", inputLine);
    //string response = "Match unfound";

    string inputLine_lowCase = toLowerCase(inputLine);

    for(int i = 0; i < taskList.size(); i++)
    {
        string stringInVec = taskList[i]->getName();
        toLowerCase(stringInVec);
		found = stringInVec.find(inputLine);
        if(found!=string::npos)
        {
            match++;
            outstr << i+1 << ". " << taskList[i]->getName() << "\n";
        }
    }

	if(match != 0)
		response = outstr.str();
        
	return response;
}

string Executor::executeClear(string &inputLine)
{
	UserInterface output;
	Validator checker;
    Storage store;
    int i = 0;
    string response;
        
    string date = extractFirstWord(inputLine);
	if(checker.isValidDate(date))
    {
		do {
        if(date == taskList[i]->getDate())
        {
			taskList.erase(taskList.begin()+i);
			response = output.generateMessage("cleared", date);
            //response = "cleared";                           //temp
        }
        else 
            i++;
		} while(i < taskList.size());
    }
    else
        response = output.generateMessage("invalidDate", date);
        //response = "invalidDate";                               //temp
        
    return response;
}

string Executor::executeDone(string &inputLine) {

	UserInterface output;
    Storage store;
    Validator checker;
    string response;

    string taskNum_str = extractFirstWord(inputLine);
    if(checker.isInt(inputLine))
    {
        int taskNum_int = makeInt(taskNum_str);
        int actual_taskNum_int = taskNum_int - 1;
        if(checker.isValidTaskNumber(actual_taskNum_int, taskList))
        {       
            string doneTask = taskList[actual_taskNum_int]->getName();
            taskList[actual_taskNum_int]->setDone(true);
            response = output.generateMessage("Done", doneTask);
			//response = "done";                                                      //temp
        }
        else
        {       
			//invalid task num string generated
            response = output.generateMessage("invalidTaskNum", taskNum_str); 
            //response = "invalidTaskNum";                                    //temp
		}
    }
    else
    {      
		//"not an int" string generated
        response = output.generateMessage("notInt", taskNum_str);
        //response = "notInt";                                                                    //temp
    }

    return response;
}

string Executor::executeHelp()
{
    UserInterface output;
	ostringstream outstr;
    string response = EMPTY;

    //output.generateMessage("help");
	response = output.generateHelpList();

 //   outstr << "add " << "[task name] " << "-date [dd/mm/yyyy] " << "or " << "-starts [hhmm] " << "or " << "-ends [hhmm] " << "or " << "-detail [detail]" << "\n";
 //   outstr << "delete " << "[task number]" << "\n";
 //   outstr << "show " << "\n";
 //   outstr << "show " << "impt" << "\n";
 //   outstr << "show " << "detail" << "\n";
 //   outstr << "show " << "[dd/mm/yyyy]" << "\n";
 //   outstr << "search " << "[part of/full task name]" << "\n";
 //   outstr << "clear " << "[dd/mm/yyyy]" << "\n";
 //   outstr << "done " << "[task number]" << "\n";

	//response = outstr.str();

    return response;
}

string Executor::executeExit()
{
    Storage store;
	store.clearLog();
    string response = "Exiting...";

    return response;
}